/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.engine.impl.bpmn.parser.factory;

import com.je.bpm.core.model.*;
import com.je.bpm.core.model.event.*;
import com.je.bpm.core.model.gateway.EventGateway;
import com.je.bpm.core.model.gateway.ExclusiveGateway;
import com.je.bpm.core.model.gateway.InclusiveGateway;
import com.je.bpm.core.model.gateway.ParallelGateway;
import com.je.bpm.core.model.message.Message;
import com.je.bpm.core.model.process.SubProcess;
import com.je.bpm.core.model.process.Transaction;
import com.je.bpm.core.model.signal.Signal;
import com.je.bpm.core.model.task.*;
import com.je.bpm.engine.ActivitiException;
import com.je.bpm.engine.delegate.BusinessRuleTaskDelegate;
import com.je.bpm.engine.delegate.Expression;
import com.je.bpm.engine.impl.bpmn.behavior.*;
import com.je.bpm.engine.impl.bpmn.behavior.SubProcessActivityBehavior;
import com.je.bpm.engine.impl.bpmn.helper.ClassDelegate;
import com.je.bpm.engine.impl.bpmn.helper.ClassDelegateFactory;
import com.je.bpm.engine.impl.bpmn.helper.DefaultClassDelegateFactory;
import com.je.bpm.engine.impl.bpmn.parser.FieldDeclaration;
import com.je.bpm.engine.impl.delegate.*;
import com.je.bpm.engine.impl.scripting.ScriptingEngines;
import com.je.bpm.engine.impl.util.ReflectUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import static java.util.Collections.emptyList;

/**
 * Default implementation of the {@link ActivityBehaviorFactory}. Used when no custom {@link ActivityBehaviorFactory} is injected on the {@link ProcessEngineConfigurationImpl}.
 */
public class DefaultActivityBehaviorFactory extends AbstractBehaviorFactory implements ActivityBehaviorFactory {

    public static final String DEFAULT_SERVICE_TASK_BEAN_NAME = "defaultServiceTaskBehavior";

    private final ClassDelegateFactory classDelegateFactory;

    public DefaultActivityBehaviorFactory(ClassDelegateFactory classDelegateFactory) {
        this.classDelegateFactory = classDelegateFactory;
    }

    public DefaultActivityBehaviorFactory() {
        this(new DefaultClassDelegateFactory());
    }

    // Start event
    public final static String EXCEPTION_MAP_FIELD = "mapExceptions";

    @Override
    public NoneStartEventActivityBehavior createNoneStartEventActivityBehavior(StartEvent startEvent) {
        return new NoneStartEventActivityBehavior();
    }

    @Override
    // Task
    public TaskActivityBehavior createTaskActivityBehavior(Task task) {
        return new TaskActivityBehavior();
    }

    @Override
    public ManualTaskActivityBehavior createManualTaskActivityBehavior(ManualTask manualTask) {
        return new ManualTaskActivityBehavior();
    }

    @Override
    public ReceiveTaskActivityBehavior createReceiveTaskActivityBehavior(ReceiveTask receiveTask) {
        return new ReceiveTaskActivityBehavior();
    }

    @Override
    public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
        return new UserTaskActivityBehavior(userTask);
    }

    // Service task

    protected Expression getSkipExpressionFromServiceTask(ServiceTask serviceTask) {
        Expression result = null;
        if (StringUtils.isNotEmpty(serviceTask.getSkipExpression())) {
            result = expressionManager.createExpression(serviceTask.getSkipExpression());
        }
        return result;
    }

    @Override
    public ClassDelegate createClassDelegateServiceTask(ServiceTask serviceTask) {
        return classDelegateFactory.create(serviceTask.getId(),
                serviceTask.getImplementation(),
                createFieldDeclarations(serviceTask.getFieldExtensions()),
                getSkipExpressionFromServiceTask(serviceTask),
                serviceTask.getMapExceptions());
    }

    @Override
    public ServiceTaskDelegateExpressionActivityBehavior createServiceTaskDelegateExpressionActivityBehavior(ServiceTask serviceTask) {
        Expression delegateExpression = expressionManager.createExpression(serviceTask.getImplementation());
        return createServiceTaskBehavior(serviceTask, delegateExpression);
    }

    @Override
    public ActivityBehavior createDefaultServiceTaskBehavior(ServiceTask serviceTask) {
        // this is covering the case where only the field `implementation` was defined in the process definition. I.e.
        // <serviceTask id="serviceTask" implementation="myServiceTaskImpl"/>
        // `myServiceTaskImpl` can be different things depending on the implementation of `defaultServiceTaskBehavior`
        // could be for instance a Spring bean or a target for a Spring Stream
        Expression delegateExpression = expressionManager.createExpression("${" + DEFAULT_SERVICE_TASK_BEAN_NAME + "}");
        return createServiceTaskBehavior(serviceTask, delegateExpression);
    }

    private ServiceTaskDelegateExpressionActivityBehavior createServiceTaskBehavior(ServiceTask serviceTask, Expression delegateExpression) {
        return new ServiceTaskDelegateExpressionActivityBehavior(serviceTask.getId(), delegateExpression,
                getSkipExpressionFromServiceTask(serviceTask),
                createFieldDeclarations(serviceTask.getFieldExtensions()));
    }

    @Override
    public ServiceTaskExpressionActivityBehavior createServiceTaskExpressionActivityBehavior(ServiceTask serviceTask) {
        Expression expression = expressionManager.createExpression(serviceTask.getImplementation());
        return new ServiceTaskExpressionActivityBehavior(serviceTask.getId(),
                expression,
                getSkipExpressionFromServiceTask(serviceTask),
                serviceTask.getResultVariableName());
    }

    // We do not want a hard dependency on Mule, hence we return
    // ActivityBehavior and instantiate the delegate instance using a string instead of the Class itself.
    @Override
    public ActivityBehavior createMuleActivityBehavior(ServiceTask serviceTask) {
        return createMuleActivityBehavior(serviceTask, serviceTask.getFieldExtensions());
    }

    @Override
    public ActivityBehavior createMuleActivityBehavior(SendTask sendTask) {
        return createMuleActivityBehavior(sendTask, sendTask.getFieldExtensions());
    }

    protected ActivityBehavior createMuleActivityBehavior(TaskWithFieldExtensions task, List<FieldExtension> fieldExtensions) {
        try {
            Class<?> theClass = Class.forName("org.activiti.mule.MuleSendActivitiBehavior");
            List<FieldDeclaration> fieldDeclarations = createFieldDeclarations(fieldExtensions);
            return (ActivityBehavior) ClassDelegate.defaultInstantiateDelegate(theClass, fieldDeclarations);
        } catch (ClassNotFoundException e) {
            throw new ActivitiException("Could not find org.activiti.mule.MuleSendActivitiBehavior: ", e);
        }
    }

    // We do not want a hard dependency on Camel, hence we return
    // ActivityBehavior and instantiate the delegate instance using a string instead of the Class itself.
    @Override
    public ActivityBehavior createCamelActivityBehavior(ServiceTask serviceTask) {
        return createCamelActivityBehavior(serviceTask, serviceTask.getFieldExtensions());
    }

    @Override
    public ActivityBehavior createCamelActivityBehavior(SendTask sendTask) {
        return createCamelActivityBehavior(sendTask, sendTask.getFieldExtensions());
    }

    protected ActivityBehavior createCamelActivityBehavior(TaskWithFieldExtensions task, List<FieldExtension> fieldExtensions) {
        try {
            Class<?> theClass = null;
            FieldExtension behaviorExtension = null;
            for (FieldExtension fieldExtension : fieldExtensions) {
                if ("camelBehaviorClass".equals(fieldExtension.getFieldName()) && StringUtils.isNotEmpty(fieldExtension.getStringValue())) {
                    theClass = Class.forName(fieldExtension.getStringValue());
                    behaviorExtension = fieldExtension;
                    break;
                }
            }

            if (behaviorExtension != null) {
                fieldExtensions.remove(behaviorExtension);
            }

            if (theClass == null) {
                // Default Camel behavior class
                theClass = Class.forName("org.activiti.camel.impl.CamelBehaviorDefaultImpl");
            }

            List<FieldDeclaration> fieldDeclarations = createFieldDeclarations(fieldExtensions);
            addExceptionMapAsFieldDeclaration(fieldDeclarations,
                    task.getMapExceptions());
            return (ActivityBehavior) ClassDelegate.defaultInstantiateDelegate( theClass, fieldDeclarations);
        } catch (ClassNotFoundException e) {
            throw new ActivitiException("Could not find org.activiti.camel.CamelBehavior: ", e);
        }
    }

    private void addExceptionMapAsFieldDeclaration(List<FieldDeclaration> fieldDeclarations, List<MapExceptionEntry> mapExceptions) {
        FieldDeclaration exceptionMapsFieldDeclaration = new FieldDeclaration(EXCEPTION_MAP_FIELD,
                mapExceptions.getClass().toString(),
                mapExceptions);
        fieldDeclarations.add(exceptionMapsFieldDeclaration);
    }

    @Override
    public ShellActivityBehavior createShellActivityBehavior(ServiceTask serviceTask) {
        List<FieldDeclaration> fieldDeclarations = createFieldDeclarations(serviceTask.getFieldExtensions());
        return (ShellActivityBehavior) ClassDelegate.defaultInstantiateDelegate(ShellActivityBehavior.class,fieldDeclarations);
    }

    @Override
    public ActivityBehavior createBusinessRuleTaskActivityBehavior(BusinessRuleTask businessRuleTask) {
        BusinessRuleTaskDelegate ruleActivity = null;
        if (StringUtils.isNotEmpty(businessRuleTask.getClassName())) {
            try {
                Class<?> clazz = Class.forName(businessRuleTask.getClassName());
                ruleActivity = (BusinessRuleTaskDelegate) clazz.newInstance();
            } catch (Exception e) {
                throw new ActivitiException("Could not instantiate businessRuleTask (id:" + businessRuleTask.getId() + ") class: " + businessRuleTask.getClassName(), e);
            }
        } else {
            // no default behavior
        }

        for (String ruleVariableInputObject : businessRuleTask.getInputVariables()) {
            ruleActivity.addRuleVariableInputIdExpression(expressionManager.createExpression(ruleVariableInputObject.trim()));
        }

        for (String rule : businessRuleTask.getRuleNames()) {
            ruleActivity.addRuleIdExpression(expressionManager.createExpression(rule.trim()));
        }

        ruleActivity.setExclude(businessRuleTask.isExclude());

        if (businessRuleTask.getResultVariableName() != null && businessRuleTask.getResultVariableName().length() > 0) {
            ruleActivity.setResultVariable(businessRuleTask.getResultVariableName());
        } else {
            ruleActivity.setResultVariable("org.activiti.engine.rules.OUTPUT");
        }

        return ruleActivity;
    }

    // Script task
    @Override
    public ScriptTaskActivityBehavior createScriptTaskActivityBehavior(ScriptTask scriptTask) {
        String language = scriptTask.getScriptFormat();
        if (language == null) {
            language = ScriptingEngines.DEFAULT_SCRIPTING_LANGUAGE;
        }
        return new ScriptTaskActivityBehavior(scriptTask.getId(),
                scriptTask.getScript(),
                language,
                scriptTask.getResultVariable(),
                scriptTask.isAutoStoreVariables());
    }

    // Gateways
    @Override
    public ExclusiveGatewayActivityBehavior createExclusiveGatewayActivityBehavior(ExclusiveGateway exclusiveGateway) {
        return new ExclusiveGatewayActivityBehavior();
    }

    @Override
    public ParallelGatewayActivityBehavior createParallelGatewayActivityBehavior(ParallelGateway parallelGateway) {
        return new ParallelGatewayActivityBehavior();
    }

    @Override
    public InclusiveGatewayActivityBehavior createInclusiveGatewayActivityBehavior(InclusiveGateway inclusiveGateway) {
        return new InclusiveGatewayActivityBehavior();
    }

    @Override
    public EventBasedGatewayActivityBehavior createEventBasedGatewayActivityBehavior(EventGateway eventGateway) {
        return new EventBasedGatewayActivityBehavior();
    }

    // Multi Instance
    @Override
    public SequentialMultiInstanceBehavior createSequentialMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) {
        return new SequentialMultiInstanceBehavior(activity, innerActivityBehavior);
    }

    @Override
    public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) {
        return new ParallelMultiInstanceBehavior(activity, innerActivityBehavior);
    }

    // Subprocess
    @Override
    public SubProcessActivityBehavior createSubprocessActivityBehavior(SubProcess subProcess) {
        return new SubProcessActivityBehavior();
    }

    @Override
    public EventSubProcessErrorStartEventActivityBehavior createEventSubProcessErrorStartEventActivityBehavior(StartEvent startEvent) {
        return new EventSubProcessErrorStartEventActivityBehavior();
    }

    @Override
    public EventSubProcessMessageStartEventActivityBehavior createEventSubProcessMessageStartEventActivityBehavior(StartEvent startEvent, MessageEventDefinition messageEventDefinition) {
        MessageExecutionContext messageExecutionContext = createMessageExecutionContext(startEvent, messageEventDefinition);
        return new EventSubProcessMessageStartEventActivityBehavior(messageEventDefinition, messageExecutionContext);
    }

    @Override
    public AdhocSubProcessActivityBehavior createAdhocSubprocessActivityBehavior(SubProcess subProcess) {
        return new AdhocSubProcessActivityBehavior();
    }

    // Call activity
    @Override
    public CallActivityBehavior createCallActivityBehavior(CallActivity callActivity) {
        String expressionRegex = "\\$+\\{+.+\\}";

        CallActivityBehavior callActivityBehaviour = null;
        if (StringUtils.isNotEmpty(callActivity.getCalledElement()) && callActivity.getCalledElement().matches(expressionRegex)) {
            callActivityBehaviour = createCallActivityBehavior(expressionManager.createExpression(callActivity.getCalledElement()), callActivity.getMapExceptions());
        } else {
            callActivityBehaviour = createCallActivityBehavior(callActivity.getCalledElement(), callActivity.getMapExceptions());
        }

        return callActivityBehaviour;
    }

    protected CallActivityBehavior createCallActivityBehavior(String calledElement, List<MapExceptionEntry> mapExceptions) {
        return new CallActivityBehavior(calledElement, mapExceptions);
    }

    protected CallActivityBehavior createCallActivityBehavior(Expression expression, List<MapExceptionEntry> mapExceptions) {
        return new CallActivityBehavior(expression, mapExceptions);
    }

    // Transaction
    @Override
    public TransactionActivityBehavior createTransactionActivityBehavior(Transaction transaction) {
        return new TransactionActivityBehavior();
    }

    // Intermediate Events
    @Override
    public IntermediateCatchEventActivityBehavior createIntermediateCatchEventActivityBehavior(IntermediateCatchEvent intermediateCatchEvent) {
        return new IntermediateCatchEventActivityBehavior();
    }

    @Override
    public IntermediateCatchMessageEventActivityBehavior createIntermediateCatchMessageEventActivityBehavior(IntermediateCatchEvent intermediateCatchEvent, MessageEventDefinition messageEventDefinition) {
        MessageExecutionContext messageExecutionContext = createMessageExecutionContext(intermediateCatchEvent, messageEventDefinition);
        return new IntermediateCatchMessageEventActivityBehavior(messageEventDefinition, messageExecutionContext);
    }

    @Override
    public IntermediateCatchTimerEventActivityBehavior createIntermediateCatchTimerEventActivityBehavior(IntermediateCatchEvent intermediateCatchEvent, TimerEventDefinition timerEventDefinition) {
        return new IntermediateCatchTimerEventActivityBehavior(timerEventDefinition);
    }

    @Override
    public IntermediateCatchSignalEventActivityBehavior createIntermediateCatchSignalEventActivityBehavior(IntermediateCatchEvent intermediateCatchEvent, SignalEventDefinition signalEventDefinition, Signal signal) {
        return new IntermediateCatchSignalEventActivityBehavior(signalEventDefinition, signal);
    }

    @Override
    public IntermediateThrowNoneEventActivityBehavior createIntermediateThrowNoneEventActivityBehavior(ThrowEvent throwEvent) {
        return new IntermediateThrowNoneEventActivityBehavior();
    }

    @Override
    public IntermediateThrowSignalEventActivityBehavior createIntermediateThrowSignalEventActivityBehavior(ThrowEvent throwEvent, SignalEventDefinition signalEventDefinition, Signal signal) {
        return new IntermediateThrowSignalEventActivityBehavior(signalEventDefinition, signal);
    }

    @Override
    public IntermediateThrowCompensationEventActivityBehavior createIntermediateThrowCompensationEventActivityBehavior(ThrowEvent throwEvent, CompensateEventDefinition compensateEventDefinition) {
        return new IntermediateThrowCompensationEventActivityBehavior(compensateEventDefinition);
    }

    // End events
    @Override
    public NoneEndEventActivityBehavior createNoneEndEventActivityBehavior(EndEvent endEvent) {
        return new NoneEndEventActivityBehavior();
    }

    @Override
    public ErrorEndEventActivityBehavior createErrorEndEventActivityBehavior(EndEvent endEvent, ErrorEventDefinition errorEventDefinition) {
        return new ErrorEndEventActivityBehavior(errorEventDefinition.getErrorRef());
    }

    @Override
    public CancelEndEventActivityBehavior createCancelEndEventActivityBehavior(EndEvent endEvent) {
        return new CancelEndEventActivityBehavior();
    }

    @Override
    public TerminateEndEventActivityBehavior createTerminateEndEventActivityBehavior(EndEvent endEvent) {
        boolean terminateAll = false;
        boolean terminateMultiInstance = false;

        if (endEvent.getEventDefinitions() != null && endEvent.getEventDefinitions().size() > 0 && endEvent.getEventDefinitions().get(0) instanceof TerminateEventDefinition) {
            terminateAll = ((TerminateEventDefinition) endEvent.getEventDefinitions().get(0)).isTerminateAll();
            terminateMultiInstance = ((TerminateEventDefinition) endEvent.getEventDefinitions().get(0)).isTerminateMultiInstance();
        }

        TerminateEndEventActivityBehavior terminateEndEventActivityBehavior = new TerminateEndEventActivityBehavior();
        terminateEndEventActivityBehavior.setTerminateAll(terminateAll);
        terminateEndEventActivityBehavior.setTerminateMultiInstance(terminateMultiInstance);
        return terminateEndEventActivityBehavior;
    }

    // Boundary Events
    @Override
    public BoundaryEventActivityBehavior createBoundaryEventActivityBehavior(BoundaryEvent boundaryEvent, boolean interrupting) {
        return new BoundaryEventActivityBehavior(interrupting);
    }

    @Override
    public BoundaryCancelEventActivityBehavior createBoundaryCancelEventActivityBehavior(CancelEventDefinition cancelEventDefinition) {
        return new BoundaryCancelEventActivityBehavior();
    }

    @Override
    public BoundaryCompensateEventActivityBehavior createBoundaryCompensateEventActivityBehavior(BoundaryEvent boundaryEvent, CompensateEventDefinition compensateEventDefinition, boolean interrupting) {
        return new BoundaryCompensateEventActivityBehavior(compensateEventDefinition, interrupting);
    }

    @Override
    public BoundaryTimerEventActivityBehavior createBoundaryTimerEventActivityBehavior(BoundaryEvent boundaryEvent,  TimerEventDefinition timerEventDefinition, boolean interrupting) {
        return new BoundaryTimerEventActivityBehavior(timerEventDefinition, interrupting);
    }

    @Override
    public BoundarySignalEventActivityBehavior createBoundarySignalEventActivityBehavior(BoundaryEvent boundaryEvent, SignalEventDefinition signalEventDefinition, Signal signal, boolean interrupting) {
        return new BoundarySignalEventActivityBehavior(signalEventDefinition, signal, interrupting);
    }

    @Override
    public BoundaryMessageEventActivityBehavior createBoundaryMessageEventActivityBehavior(BoundaryEvent boundaryEvent, MessageEventDefinition messageEventDefinition, boolean interrupting) {
        MessageExecutionContext messageExecutionContext = createMessageExecutionContext(boundaryEvent, messageEventDefinition);
        return new BoundaryMessageEventActivityBehavior(messageEventDefinition, interrupting, messageExecutionContext);
    }

    @Override
    public IntermediateThrowMessageEventActivityBehavior createThrowMessageEventActivityBehavior(ThrowEvent throwEvent, MessageEventDefinition messageEventDefinition, Message message) {
        ThrowMessageDelegate throwMessageDelegate = createThrowMessageDelegate(messageEventDefinition);
        MessageExecutionContext messageExecutionContext = createMessageExecutionContext(throwEvent, messageEventDefinition);
        return new IntermediateThrowMessageEventActivityBehavior(throwEvent, messageEventDefinition, throwMessageDelegate, messageExecutionContext);
    }

    @Override
    public ThrowMessageEndEventActivityBehavior createThrowMessageEndEventActivityBehavior(EndEvent endEvent, MessageEventDefinition messageEventDefinition, Message message) {
        ThrowMessageDelegate throwMessageDelegate = createThrowMessageDelegate(messageEventDefinition);
        MessageExecutionContext messageExecutionContext = createMessageExecutionContext(endEvent, messageEventDefinition);
        return new ThrowMessageEndEventActivityBehavior(endEvent, messageEventDefinition, throwMessageDelegate, messageExecutionContext);
    }

    protected ThrowMessageDelegate createThrowMessageDelegate(MessageEventDefinition messageEventDefinition) {
        Map<String, List<ExtensionAttribute>> attributes = messageEventDefinition.getAttributes();
        return checkClassDelegate(attributes)
                .map(this::createThrowMessageJavaDelegate).map(Optional::of)
                .orElseGet(() -> checkDelegateExpression(attributes).map(this::createThrowMessageDelegateExpression))
                .orElseGet(this::createDefaultThrowMessageDelegate);
    }

    public MessageExecutionContext createMessageExecutionContext(Event bpmnEvent, MessageEventDefinition messageEventDefinition) {
        MessagePayloadMappingProvider mappingProvider = createMessagePayloadMappingProvider(bpmnEvent, messageEventDefinition);
        return getMessageExecutionContextFactory().create(messageEventDefinition, mappingProvider, expressionManager);
    }

    public ThrowMessageDelegate createThrowMessageJavaDelegate(String className) {
        Class<? extends ThrowMessageDelegate> clazz = ReflectUtil.loadClass(className).asSubclass(ThrowMessageDelegate.class);
        return new ThrowMessageJavaDelegate(clazz, emptyList());
    }

    public ThrowMessageDelegate createThrowMessageDelegateExpression(String delegateExpression) {
        Expression expression = expressionManager.createExpression(delegateExpression);
        return new ThrowMessageDelegateExpression(expression, emptyList());
    }

    public ThrowMessageDelegate createDefaultThrowMessageDelegate() {
        return getThrowMessageDelegateFactory().create();
    }

    public MessagePayloadMappingProvider createMessagePayloadMappingProvider(Event bpmnEvent, MessageEventDefinition messageEventDefinition) {
        return getMessagePayloadMappingProviderFactory().create(bpmnEvent, messageEventDefinition, getExpressionManager());
    }

    @Override
    public KaiteUserTaskActivityBehavior createKaiteUserTaskActivityBehavior(KaiteUserTask kaiteUserTask) {
        return new KaiteUserTaskActivityBehavior(kaiteUserTask);
    }

    @Override
    public KaiteMultiUserTaskActivityBehavior createKaiteMultiUserTaskActivityBehavior(KaiteMultiUserTask kaiteMultiUserTask) {
        return new KaiteMultiUserTaskActivityBehavior(kaiteMultiUserTask);
    }

    @Override
    public KaiteLoopUserTaskActivityBehavior createKaiteLoopUserTaskActivityBehavior(KaiteLoopUserTask kaiteLoopUserTask) {
        return new KaiteLoopUserTaskActivityBehavior(kaiteLoopUserTask);
    }

    @Override
    public KaiteFixedUserTaskActivityBehavior createKaiteFixedUserTaskActivityBehavior(KaiteFixedUserTask kaiteFixedUserTask) {
        return new KaiteFixedUserTaskActivityBehavior(kaiteFixedUserTask);
    }

    @Override
    public KaiteRandomUserTaskActivityBehavior createKaiteRandomUserTaskActivityBehavior(KaiteRandomUserTask kaiteRandomUserTask) {
        return new KaiteRandomUserTaskActivityBehavior(kaiteRandomUserTask);
    }

    @Override
    public KaiteDecideUserTaskActivityBehavior createKaiteDecideUserTaskActivityBehavior(KaiteDecideUserTask kaiteDecideUserTask) {
        return new KaiteDecideUserTaskActivityBehavior(kaiteDecideUserTask);
    }

    @Override
    public KaiteCounterSignUserTaskActivityBehavior createKaiteCounterSignUserTaskActivityBehavior(KaiteCounterSignUserTask kaiteCounterSignUserTask) {
        return new KaiteCounterSignUserTaskActivityBehavior(kaiteCounterSignUserTask);
    }

    @Override
    public KaiteCandidateUserTaskActivityBehavior createKaiteCandidateUserTaskActivityBehavior(KaiteCandidateUserTask kaiteCandidateUserTask) {
        return new KaiteCandidateUserTaskActivityBehavior(kaiteCandidateUserTask);
    }

    protected Optional<String> checkClassDelegate(Map<String, List<ExtensionAttribute>> attributes) {
        return getAttributeValue(attributes, "class");
    }

    protected Optional<String> checkDelegateExpression(Map<String, List<ExtensionAttribute>> attributes) {
        return getAttributeValue(attributes, "delegateExpression");
    }

    protected Optional<String> getAttributeValue(Map<String, List<ExtensionAttribute>> attributes, String name) {
        return Optional.ofNullable(attributes)
                .filter(it -> it.containsKey("activiti"))
                .map(it -> it.get("activiti"))
                .flatMap(it -> it.stream()
                        .filter(el -> name.equals(el.getName()))
                        .findAny())
                .map(ExtensionAttribute::getValue);
    }
}
